#include "call.h"

Call::Call()
{
	_proto.push_back(Protocol::CALL);
	_operator[Operator::SOUND] = &Call::sound;
	_operator[Operator::CALL] = &Call::call;
	_operator[Operator::CONNECT] = &Call::opConnect;
	_operator[Operator::ENDCALL] = &Call::endCall;
	_clientSelected = -1;
	_isCall = false;
}

Call::~Call()
{

}

#if defined __linux__
extern "C"  IModule* getCall()
#else
extern "C" __declspec(dllexport) IModule* getCall()
#endif
{
	return new Call();
}

void					Call::setApi(BabelApi *api)
{
	_api = api;
	connect(dynamic_cast<QObject*>(_api->audio), SIGNAL(_inputReady(ISoundPacket *)), this, SLOT(inputReady(ISoundPacket *)));
	connect(dynamic_cast<QObject*>(_api->gui), SIGNAL(_emitClient(unsigned int)), this, SLOT(selectedClient(unsigned int)));
}

void					Call::init()
{
	addMenuCall();
	addButtonCall();
	addButtonHangup();
	_api->gui->addMenu(_menu);
	_api->gui->addWidget(_buttoncall);
	_api->gui->addWidget(_buttonhangup);
}

void					Call::selectedClient(unsigned int id)
{
	std::cout << "ID Selected : " << id << std::endl;
	_clientSelected = id;
}

void					Call::takeOrder(IOrder *order, Protocol protocol)
{
	Operator			op = *(Operator*)order->getData(sizeof(byte));

	if (_operator.find((Operator) op) != _operator.end())
		(this->*_operator[(Operator) op])(order);
	delete order;
}



void					Call::test()
{
	std::cout << "SUCCESS TEST" << std::endl;
}

std::vector<Protocol>	Call::getProtocol() const
{
	return _proto;
}

void					Call::inputReady(ISoundPacket *packet)
{
	IEncodedSoundPacket *encpacket = _api->audio->encode(packet);
	IOrder				*order = _api->network->getIOrder();
	Protocol			proto = Protocol::CALL;
	Operator			op = Call::SOUND;
	unsigned short		len = encpacket->len();
	unsigned int		ts = _api->timestamp + _api->time.elapsed();

	order->init();
	order->pushData((void*)&proto, sizeof(proto));
	order->pushData((void*)&op, sizeof(op));
	order->pushData((void*)&ts, sizeof(ts));
	order->pushData((void*) &len, sizeof(len));
	order->pushData(encpacket->data(), encpacket->len());
	_api->network->UdpSend(order);
}

void					Call::addMenuCall()
{
	_menu = new QMenu("Call");
	_call = _menu->addAction("Call");
	_hangup = _menu->addAction("Hang up");

	connect(_call, SIGNAL(triggered()), this, SLOT(OnCallActionTriggered()));
	connect(_hangup, SIGNAL(triggered()), this, SLOT(OnHangUpActionTriggered()));
}

void					Call::addButtonCall()
{
	_buttoncall = new QPushButton("Call");

	_buttoncall->setStyleSheet("border: 2px solid #8f8f91; border-radius: 6px; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); min-width: 80px;");
	connect(_buttoncall, SIGNAL(clicked()), this, SLOT(OnCallButtonClicked()));
	_buttoncall->show();
}

void					Call::addButtonHangup()
{
	_buttonhangup = new QPushButton("Hang-up");

	_buttonhangup->setStyleSheet("border: 2px solid #8f8f91; border-radius: 6px; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); min-width: 80px;");
	connect(_buttonhangup, SIGNAL(clicked()), this, SLOT(OnHangUpButtonClicked()));
	_buttonhangup->show();
}

void					Call::OnCallActionTriggered()
{
	std::cout << "Call Action Triggered" << std::endl;
}

void					Call::OnHangUpActionTriggered()
{
	std::cout << "Hang up Action Triggered" << std::endl;
}

void					Call::OnCallButtonClicked()
{
	std::cout << "Call button clicked" << std::endl;
	Protocol			proto = Protocol::CALL;
	Operator			op = Operator::CALL;
	if (_clientSelected != -1 && _isCall == false)
	{
		IOrder				*order = _api->network->getIOrder();
		unsigned int		id = _clientSelected;
//		unsigned int		id = 0;

		order->init();
		order->pushData(&proto, sizeof(Protocol));
		order->pushData(&op, sizeof(op));
		order->pushData(&id, sizeof(id));
		_api->network->TcpSend(order);
		_isCall = true;
		_idCall = _clientSelected;
		std::string text("");
		text += "Call : ";
		text += (*_api->client)[id]->getName();
		_buttoncall->setText(QString(text.c_str()));
	/*std::cout << "finding client " << id << "in database" << std::endl;
	IClient			*client = (*_api->client)[id];
	std::cout << "Sending a call to " << id << std::endl;
	_api->audio->setInput(true);
	_api->audio->setOutput(true);
	std::cout << "appel vers " << client->getIp() << std::endl;*/

	}
	else if (_isCall == true)
	{
		IOrder				*newOrder = _api->network->getIOrder();

		newOrder->init();
		newOrder->pushData(&proto, sizeof(Protocol));
		newOrder->pushData(&op, sizeof(op));
		newOrder->pushData(&_idCall, sizeof(_idCall));
		_api->network->TcpSend(newOrder);
	}
}

void					Call::OnHangUpButtonClicked()
{
	std::cout << "Hang-up button clicked" << std::endl;
	if (_isCall == true)
	{
		IOrder			*newOrder = _api->network->getIOrder();
		Protocol		proto = Protocol::CALL;
		Operator		op = ENDCALL;

		newOrder->init();
		newOrder->pushData(&proto, sizeof(Protocol));
		newOrder->pushData(&op, sizeof(Operator));
		newOrder->pushData(&_idCall, sizeof(_idCall));
		_api->network->TcpSend(newOrder);
	}
}

void					Call::sound(IOrder *order)
{
	unsigned int		ts = *(unsigned int*) order->getData(sizeof(ts));
	unsigned short		*len = (unsigned short*)order->getData(sizeof(unsigned short));
	byte				*input = (byte*)order->getData(*len);
	IEncodedSoundPacket	*enc = _api->audio->getIEncodedSoundPacket();
	enc->setData(input);
	enc->setLen(*len);
	ISoundPacket		*newpacket = _api->audio->decode(enc);
	_api->audio->play(newpacket, ts);
}

void					Call::call(IOrder *order)
{
	unsigned int	id = *(unsigned int*)order->getData(sizeof(id));
	if (_api->client->find(id))
	{
		std::string		pick("");
		pick = "pick up : ";
		pick += (*_api->client)[id]->getName();
		_buttoncall->setText(QString(pick.c_str()));
		_idCall = id;
		_isCall = true;
	}
	else
	{
		IOrder			*newOrder = _api->network->getIOrder();
		Protocol		proto = Protocol::CALL;
		Operator		op = ENDCALL;

		newOrder->init();
		newOrder->pushData(&proto, sizeof(Protocol));
		newOrder->pushData(&op, sizeof(Operator));
		newOrder->pushData(&id, sizeof(id));
		_api->network->TcpSend(newOrder);
	}
}

void					Call::endCall(IOrder *order)
{
	unsigned int id = *(unsigned int*)order->getData(sizeof(id));

	std::cout << "HANG UP !!!!!!!!!!!!" << std::endl;
	std::cout << "intern : " << _idCall << " extern : " << id << std::endl;
	if (id == _idCall && _isCall == true)
	{
		_api->audio->setInput(false);
		_api->audio->setOutput(false);
		_api->network->disconnect(id);
		_isCall = false;
		_buttoncall->setText(QString("Call"));
	}
}

void					Call::opConnect(IOrder *order)
{
	std::cout << "received msg of size " << order->size() << std::endl;
	unsigned int id = *(unsigned int*)order->getData(sizeof(id));
	std::cout << "finding client " << id << "in database" << std::endl;
	IClient			*client = (*_api->client)[id];
	std::cout << "Received a call from " << id << std::endl;
	_api->audio->setInput(true);
	_api->audio->setOutput(true);
	std::cout << "appel vers " << client->getIp() << std::endl;
	_api->network->ConnectToClient(client->getIp(), "4243");
}
